/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package picturemouse;

import java.util.ArrayList;
import java.util.Arrays;

/**
 *
 * @author Duncan
 */
public class PictureMouse {
    
    private static Film[] films = new Film[0];
    private static Screening[] screenings = new Screening[0];
    private static Screen[] screens = new Screen[0];
    private static Seat[] seats = new Seat[0];
    private static Booking[] bookings = new Booking[0];
    private static Review[] reviews;
    private static Account[] accounts = new Account[0];

    /**
     * @param args the command line arguments
     * @throws picturemouse.ScreenAlreadyExistsException
     * @throws picturemouse.SeatAlreadyExistsException
     * @throws picturemouse.FilmAlreadyExistsException
     * @throws picturemouse.FilmNotFoundException
     * @throws picturemouse.SeatNotAvaliableException
     * @throws picturemouse.ScreeningNotFoundException
     */
    public static void main(String[] args) throws ScreenAlreadyExistsException, SeatAlreadyExistsException, FilmAlreadyExistsException, FilmNotFoundException, SeatNotAvaliableException, ScreeningNotFoundException {
        
   	
        //Create some screens
        addScreen(1);
        addScreen(2);
        addScreen(3);
        
        //Create some seats
        addSeat("A", 1, 1); //Seat A1 in screen 1
        addSeat("A", 2, 1); //Seat A2 in screen 1
        addSeat("A", 3, 1); //Seat A3 in screen 1
        addSeat("A", 1, 2); //Seat A1 in screen 2
        addSeat("A", 2, 2); //Seat A2 in screen 2
        addSeat("A", 3, 2); //Seat A3 in screen 2
        addSeat("A", 1, 3); //Seat A1 in screen 3
        addSeat("A", 2, 3); //Seat A2 in screen 3
        addSeat("A", 3, 3); //Seat A3 in screen 3
        
        //Create some films
        addFilm("Fargo", "Jerry Lundegaard's inept crime falls apart due to his and his henchmen's"
                + " bungling and the persistent police work of the quite pregnant Marge Gunderson.", "http://www.youtube.com/watch?v=EB4PmbfG4bw");
        addFilm("Inception", "A skilled extractor is offered a chance to regain" 
                + " his old life as payment for a task considered to be impossible.", "http://www.youtube.com/watch?v=8hP9D6kZseM");
        addFilm("Lawless", "Set in Depression-era Franklin County, Virginia, a bootlegging gang" 
                + " is threatened by a new deputy and other authorities who want a cut of their profits.", "http://www.youtube.com/watch?v=4Zl7S1LaPMU");
        
        //Create some screenings
        addScreening(films[0].getName(), "12:00 05/03/2014", 1);
        addScreening(films[0].getName(), "16:00 05/03/2014", 1);  
        addScreening(films[1].getName(), "12:45 05/03/2014", 2);  
        addScreening(films[1].getName(), "18:30 05/03/2014", 2);  
        addScreening(films[2].getName(), "11:10 05/03/2014", 3);  
        addScreening(films[2].getName(), "14:20 05/03/2014", 3);
        
        //Create some bookings
        addBooking(0, "Bobby", 1);
        addBooking(3, "Fred", 5);
        addBooking(5, "Matilda", 7);
        
    }
    
    /*
    Method to return a Film object from the film's name    
    */
    public static Film getFilmByName(String filmName) throws FilmNotFoundException {
        //Loop the films
        for (Film film : films) {
            if (film.getName().equals(filmName)) {
                //If the film name matches the desired name, return the film object
                return film;
            }
        }
        //If it get's here, the film name wasn't matched, so throw an exception
        throw new FilmNotFoundException();
    }
    
    /*
    Method to return an array of seat IDs for a given screen number    
    */
    public static Integer[] getSeatsByScreenNum(int screenNum) {
        ArrayList<Integer> seatList = new ArrayList<>();
        //Loop the seats
        for (Seat seat : seats) {
            if (seat.getScreenNum()==screenNum) {
                //If the seat ID matches the desired ID, add the seat to the list
                seatList.add(seat.getID());
            }
        }
        //Return the list as an array of Integers
        return seatList.toArray(new Integer[0]);
    }
    
    /*
    Method to return a Screen object from the screen num    
    */
    public static Screen getScreenByNum(int screenNum) throws ScreenNotFoundException {
        //Loop the screens
        for (Screen screen : screens) {
            if (screen.getScreenNum()==screenNum) {
                //If the screen number matches the desired number, return the screen object
                return screen;
            }
        }
        //If it get's here, the screen numer wasn't matched, so throw an exception
        throw new ScreenNotFoundException();
    }
    
    /*
    Method to return a Seat object from the seat's ID    
    */
    public static Seat getSeatByID(int seatID) throws SeatNotFoundException {
        //Loop the seats
        for (Seat seat : seats) {
            if (seat.getID()==seatID) {
                //If the seat ID matches the desired ID, return the seat object
                return seat;
            }
        }
        //If it get's here, the seat ID wasn't matched, so throw an exception
        throw new SeatNotFoundException();
    }
    
    /*
    Method to return a Screening object from the screening ID    
    */
    public static Screening getScreeningByID(int screeningID) throws ScreeningNotFoundException {
        //Loop the screenings
        for (Screening screening : screenings) {
            if (screening.getID()==screeningID) {
                //If the screening ID matches the desired ID, return the screening object
                return screening;
            }
        }
        //If it get's here, the screening ID wasn't matched, so throw an exception
        throw new ScreeningNotFoundException();
    }
    
    /**
    * Method to return a Booking object from the booking ID    
     * @param bookingID
     * @return Booking object which matches the given bookingID
     * @throws picturemouse.BookingNotFoundException
    */
    public static Booking getBookingByID(int bookingID) throws BookingNotFoundException {
        //Loop the bookings
        for (Booking booking : bookings) {
            if (booking.getID()==bookingID) {
                //If the booking ID matches the desired ID, return the booking object
                return booking;
            }
        }
        //If it get's here, the booking ID wasn't matched, so throw an exception
        throw new BookingNotFoundException();
    }
    
    /*
    Method to return an Account object from the customer's name    
    */
    public static Account getAccountByName(String customerName) throws AccountNotFoundException {
        //Loop the accounts
        for (Account account : accounts) {        		
        		if (account.getCustomerName().equals(customerName)) {
                //If the customer name matches the desired name, return the account object

            	return account;
            }
        }
        //If it get's here, the film name wasn't matched, so throw an exception
        throw new AccountNotFoundException();
    }
    
    //Get Methods for retrieving the arrays which store the data for the system
    
    public static Film[] getFilmArray() {
        return films;
    }
    
    public static Screening[] getScreeningArray() {
        return screenings;
    }
    
    public static Screen[] getScreenArray() {
        return screens;
    }
    
    public static Seat[] getSeatArray() {
        return seats;
    }
    
    public static Booking[] getBookingArray() {
        return bookings;
    }
    
    
    //Set methods, for adding data to the system
    
    /**
     * Method to add a new film to the system.
     * First checks that the film doesn't already exist in the system.
     * @param filmName
     * @param synopsis
     * @param trailer
     * @throws picturemouse.FilmAlreadyExistsException
     */
    public static void addFilm(String filmName, String synopsis, String trailer) throws FilmAlreadyExistsException {
        try {
            getFilmByName(filmName);
        } catch (FilmNotFoundException e) {
            //If this error is caught, the film doesn't already exist
            //Add the film to the system
            ArrayList<Film> temp = new ArrayList<>(Arrays.asList(films)); //Convert array to ArrayList for easy adding of new element
            temp.add(new Film(filmName, synopsis, trailer)); //Add the new film element to the ArrayList
            films = temp.toArray(new Film[0]); //Overwrite the films array with the new array
            return;
        }
        throw new FilmAlreadyExistsException();
    }
    
    
    /**
     * Method to add a new seat to the system.
     * First checks that the seat doesn't already exist.
     * @param seatRow
     * @param seatNum
     * @param screenNum
     * @return Returns the seat ID
     * @throws SeatAlreadyExistsException 
     */
    public static int addSeat(String seatRow, int seatNum, int screenNum) throws SeatAlreadyExistsException {
        //Loop the seats
        for (int seatID : getSeatsByScreenNum(screenNum)) {
            if (seats[seatID].getRow().equals(seatRow) && seats[seatID].getNumber()==seatNum) {
                //If the seat data matches, throw exception
                throw new SeatAlreadyExistsException();
            }
        }
        //If it gets here, the seat doesn't already exist so add it
        int newSeatIndex = seats.length;
        ArrayList<Seat> temp = new ArrayList<>(Arrays.asList(seats)); //Convert array to ArrayList for easy adding of new element
        temp.add(new Seat(newSeatIndex, seatRow, seatNum, screenNum)); //Add the new seat element to the ArrayList
        seats = temp.toArray(new Seat[0]); //Overwrite the seats array with the new array
        return newSeatIndex;
    }
    
    
    /**
     * Method to add a new screening to the system.
     * First checks the film exists.
     * @param filmName
     * @param time
     * @param screenNum
     * @return Returns the ID of the new screening
     * @throws FilmNotFoundException 
     */
    public static int addScreening(String filmName, String time, int screenNum) throws FilmNotFoundException {
        //First, check the film exists
        getFilmByName(filmName); //If it doesn't exist, an exception will be thrown
        //Film exists, so add the screening
        int newScreeningIndex = screenings.length;
        ArrayList<Screening> temp = new ArrayList<>(Arrays.asList(screenings)); //Convert array to ArrayList for easy adding of new element
        temp.add(new Screening(newScreeningIndex, filmName, time, screenNum)); //Add the new seat element to the ArrayList
        screenings = temp.toArray(new Screening[0]); //Overwrite the seats array with the new array
        return newScreeningIndex;
    }
    
    
    /**
     * Method to add a new screen to the system.
     * Checks the screen number doesn't already exist first.
     * @param screenNum
     * @throws ScreenAlreadyExistsException 
     */
    public static void addScreen(int screenNum) throws ScreenAlreadyExistsException {
        try {
            getScreenByNum(screenNum);
        } catch (ScreenNotFoundException e) {
            //If this error is caught, the screen doesn't already exist
            //Add the screen to the system
            ArrayList<Screen> temp = new ArrayList<>(Arrays.asList(screens)); //Convert array to ArrayList for easy adding of new element
            temp.add(new Screen(screenNum)); //Add the new screen element to the ArrayList
            screens = temp.toArray(new Screen[0]); //Overwrite the films array with the new array
            return;
        }
        throw new ScreenAlreadyExistsException();
    }
    
    
    /**
     * Method to add a new booking to the system.
     * @param screeningID
     * @param customerName
     * @param seatID
     * @return Returns the ID of the booking
     * @throws SeatNotAvaliableException
     * @throws ScreeningNotFoundException 
     */
    public static int addBooking(int screeningID, String customerName, int seatID) throws SeatNotAvaliableException, ScreeningNotFoundException {
        int newBookingIndex = bookings.length;
        ArrayList<Booking> temp = new ArrayList<>(Arrays.asList(bookings)); //Convert array to ArrayList for easy adding of new element
        Booking newBooking = new Booking(newBookingIndex); //Create a new booking object
        newBooking.makeBooking(screeningID, customerName, seatID); //Adds the details to the booking, and books the seat
        temp.add(newBooking); //Add the new booking object to the ArrayList
        bookings = temp.toArray(new Booking[0]); //Overwrite the seats array with the new array
        return newBookingIndex;
    }
    
    /**
     * Method to add an account to the system.
     * First checks the account doesn't exist.
     * @param name
     * @param pwd
     * @param ccNo
     * @throws AccountAlreadyExistsException
     * @throws InvalidCardNumberException 
     */
    public static void addAccount(String name, String pwd, String ccNo) throws AccountAlreadyExistsException, InvalidCardNumberException, InvalidPasswordException {
        try {
            getAccountByName(name);
        } catch (AccountNotFoundException e) {
            //If this error is caught, the account doesn't already exist
            //Add the account to the system
            ArrayList<Account> temp = new ArrayList<>(Arrays.asList(accounts)); //Convert array to ArrayList for easy adding of new element
            temp.add(new Account(name, pwd, ccNo)); //Add the new account element to the ArrayList
            accounts = temp.toArray(new Account[0]); //Overwrite the accounts array with the new array
            return;
        }
        throw new AccountAlreadyExistsException();
    }
    
}
